package club.pinea.server;

import club.pinea.constants.OrderConstants;
import club.pinea.model.Seat;
import club.pinea.pool.ProtoPoolExecutor;
import club.pinea.proto.BasicProto.BaseMessage;
import club.pinea.proto.CommandProto;
import club.pinea.service.SeatService;
import club.pinea.service.UserService;
import club.pinea.session.GlobalServerPlayerContainer;
import club.pinea.session.GlobalSessionContainer;
import club.pinea.session.IOSession;
import club.pinea.utils.AsyncManager;
import com.alibaba.fastjson.JSONObject;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.Assert;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimerTask;

/**
 * @author pineapple
 * @date 2017年12月26日 下午1:30:07
 * @description 服务端的业务处理类
 */
//@Component
//@ChannelHandler.Sharable
public class LobbyServerHandler extends SimpleChannelInboundHandler<BaseMessage> {

    @Autowired
    private ProtoPoolExecutor protoPoolExecutor;

    /**
     * 用户操作服务类
     */
    @Autowired
    private UserService userService;

    /**
     * redis座位操作服务类
     */
    @Autowired
    private SeatService seatService;

    /**
     * 日志记录对象
     */
    private static Logger logger = LoggerFactory.getLogger(LobbyServerHandler.class);

    /**
     * 当前用户的ID
     */
    private int userId;

    /**
     * 用户名称
     */
    private String userName;

    @Value("${server.game.port}")
    public Integer gamePort;

    @Value("${server.game.minScore}")
    public Integer minScore;

    @Value("${server.game.maxScore}")
    public Integer maxScore;

    /**
     * 当前超时的次数
     */
    private int nowTime = 0;

    /**
     * 当前用户是否坐在某个座位上
     */
    private Seat seat;

    private String token = null;

    /**
     * 当有客户端注册服务端时触发
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        IOSession session = GlobalSessionContainer.getIOSession(ctx.hashCode());
        if (session == null) {
            session = this.createIOSession(ctx);
            GlobalSessionContainer.addIOSession(session);
        }
    }

    private IOSession createIOSession(ChannelHandlerContext ctx) {
        IOSession session = new IOSession();
        session.setContext(ctx);
        session.setType(IOSession.SessionType.SOCKET);
        return session;
    }


    /**
     * 当有客户端数据传入时触发
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, BaseMessage message) throws Exception {
        IOSession session = GlobalSessionContainer.getIOSession(ctx.hashCode());
        if (session == null) {
            session = this.createIOSession(ctx);
            GlobalSessionContainer.addIOSession(session);
        }

        // 在room命令中执行新建user操作
        if (message.getOrder() != CommandProto.Command.C_S_HEART_VALUE && message.getOrder() != CommandProto.Command.C_S_ROOM_VALUE) {
            Assert.notNull(GlobalServerPlayerContainer.getServerPlayer(session), "用户未登录");
        }

        protoPoolExecutor.doTask(session, message);
    }

    /**
     * 像流里面写数据
     *
     * @param ctx
     * @param msg
     */
    private void writeAndFlush(ChannelHandlerContext ctx, String msg) {
        ctx.writeAndFlush(msg);
    }

    /**
     * 进入房间的指令操作方法
     *
     * @param ctx 操作读写对象
     * @param obj json对象
     */
    private void getInRoom(ChannelHandlerContext ctx, JSONObject obj) {
        int roomNum = obj.getInteger("room");
        if (roomNum <= 0 || roomNum > 3) {
            throw new IllegalArgumentException("参数错误：room:" + roomNum);
        }
        userId = obj.getInteger("id");
        List<Seat> seatList = seatService.getRoomSeatDownSeatsByKey(roomNum);//获取当前数据库中有人坐的座位

        obj = new JSONObject();
        //判断是否是正确的User对象，如果为空则返回失败信息，否则返回正确信息以及端口号和用户对象
        int multiplyPower = selectMutiplyPower(roomNum);
        obj.put("order", "success");
        Map<String, Object> m = new HashMap<>();
        m.put("seats", seatList);
        m.put("userNum", seatList.size());
        m.put("multiplyPower", multiplyPower);
        obj.put("room", m);
        writeAndFlush(ctx, obj.toString());
    }

    /**
     * 根据房间号判断房间倍率
     *
     * @param room
     * @return
     */
    private int selectMutiplyPower(int room) {
        switch (room) {//根据房间号判断房间倍率
            case 1:
                return 20;
            case 2:
                return 5;
            case 3:
                return 2;
        }
        return 0;
    }

    /**
     * 读取指令判断调用方法
     *
     * @param ctx   channelhandlercontext独享
     * @param obj   json对象
     * @param order 指令
     * @throws Exception
     */
    public void readOrder(ChannelHandlerContext ctx, JSONObject obj, String order) throws Exception {
        //加载属性文件中的命令并判断是否是进入房间命令

        if (OrderConstants.ROOM.equals(order)) {
            getInRoom(ctx, obj);
        } else if (OrderConstants.LEAVE_SEAT.equals(order)) {
            leaveSeat(ctx, obj);
        } else if (OrderConstants.HEART.equals(order)) {
        } else if (OrderConstants.SEAT.equals(order)) {
            seatDown(ctx, obj);
        } else if (OrderConstants.EXIT.equals(order)) {
            userLogout(ctx, obj);
        } else if (OrderConstants.UPDATE_ROOM_INFO.equals(order)) {
            updateRoomInfo(ctx, obj);
        } else if (OrderConstants.LEAVE_ROOM.equals(order)) {
            if (seat != null) {
                seat.setSeatStatus(0);
                seat.setSeatUser(null);
//                seatService.updateSeat(seat, seat.getSeatId(), true);//更新数据库中的座位信息状态
                seat = null;
            }
        } else if (OrderConstants.STAY_SEAT.equals(order)) {
            staySeat(ctx, obj);
        } else {
            throw new IllegalArgumentException("\"" + order + "\"命令不正确，不能处理的命令");
        }
    }

    /**
     * 座位留机处理
     *
     * @param ctx
     * @param obj
     */
    private void staySeat(ChannelHandlerContext ctx, JSONObject obj) throws Exception {
        int seatId = obj.getInteger("seatNum");
        int userId = obj.getInteger("id");
        int staySeatTime = userService.selectStaySeatTimeById(userId);
        if (staySeatTime < 0) {
            throw new IllegalArgumentException("今日留机次数已用完，留机失败！");
        }
//        seatService.updateSeatsInfoForStaySeat(userName, seatId, );
        Seat s = new Seat(seat.getSeatId());
        AsyncManager.me().executeDelay(new TimerTask() {
            @Override
            public void run() {
//                int result = seatService.formatSeatByStaySeats(s, seatId);//更新座位信息
//                if (result > 0) {
//                }
            }
        });
        seat = null;
        writeAndFlush(ctx, "{\"order\":\"success\"}");
    }

    /**
     * 用户正常退出操作
     *
     * @param ctx
     * @param obj
     */
    private void userLogout(ChannelHandlerContext ctx, JSONObject obj) {
        userService.UserLogout(userId, 0);//用户直接离线，直接控制座位信息清空
        if (seat != null) {
            seat.setSeatStatus(0);
            seat.setSeatUser(null);
//            seatService.updateSeat(seat, seat.getSeatId(), false);//更新数据库中的座位信息状态
            seat = null;
        }
        userId = 0;
    }

    /**
     * 更新大厅信息
     *
     * @param ctx
     * @param obj
     */
    private void updateRoomInfo(ChannelHandlerContext ctx, JSONObject obj) {
        int roomId = obj.getInteger("room");
        List<Seat> seatList = seatService.getRoomSeatDownSeatsByKey(roomId);
        obj = new JSONObject();
        obj.put("order", "success");
        Map<String, Object> m = new HashMap<>();
        m.put("seats", seatList);
        m.put("userNum", seatList.size());
        m.put("multiplyPower", selectMutiplyPower(roomId));
        obj.put("room", m);//重新获取座位信息返回客户端
        writeAndFlush(ctx, obj.toString());
    }

    /**
     * 离开座位请求
     *
     * @param ctx
     * @param obj
     */
    private void leaveSeat(ChannelHandlerContext ctx, JSONObject obj) {
        //将该座位制空
        int seatId = obj.getInteger("seatNum");
//        seat = seatService.getSeatBean(seatId);
        seat.setSeatStatus(0);
        seat.setSeatUser(null);
//        seatService.updateSeat(seat, seatId, true);//更新数据库中的座位信息状态
        seat = null;//将当前连接状态中的坐状态设置为正在坐
        obj = new JSONObject();
        obj.put("order", "success");
        obj.put("money", userService.getMoneyById(userId));
        writeAndFlush(ctx, obj.toString());
    }

    /**
     * 请求进入座位开始游戏 进入座位成功增加房间玩家数量
     *
     * @param ctx 通信读写对象
     * @param obj json对象
     * @throws IOException
     * @throws FileNotFoundException
     */
    private void seatDown(ChannelHandlerContext ctx, JSONObject obj) throws FileNotFoundException, IOException {
        int num = obj.getInteger("seatNum");
//        Seat seat = seatService.getSeatBean(num);
        boolean seatLogic = false;
        if (seat == null) {
            throw new IllegalArgumentException("参数错误，没有找到该座位信息：id-" + num);
        }
        if (seat.getSeatStatus() == 2 && num == seat.getSeatId()) {
            throw new IllegalArgumentException("参数错误，您不能进入其他用户正在留机的座位哦！");
        }

        //如果当前座位没人坐，则将座位状态改变并进入座位
        if (!checkSeated(seat)) {
            seatLogic = seatDown(seat);
        }
        obj = new JSONObject();
        if (seatLogic) {
            obj.put("order", "success");
            obj.put("gamePort", gamePort);
            obj.put("maxScore", maxScore);
            obj.put("minScore", minScore);
            obj.put("bonus", seatService.selPoolScores(seat.getSeatId(), 0));
        } else {
            obj.put("order", "error");
            obj.put("message", "当前座位已有人坐");
            obj.put("seats", seatService.getRoomSeatDownSeatsByKey(num / 30 + 1));
        }
        writeAndFlush(ctx, obj.toString());
    }


    /**
     * 判断是否当前座位已有人坐
     *
     * @param seat 通过传入的座位号获取的座位信息
     * @return true 有人坐 false 没人坐
     */
    private boolean checkSeated(Seat seat) {
        return seat.getSeatStatus() == 1 && seat.getSeatUser() != null;
    }

    /**
     * 进入座位改变座位当前状态 将当前座位状态改变，并将当前座位的用户名称设置
     *
     * @param seat 通过传入的座位号获取的座位信息
     * @return true 状态改变成功 false 状态改变失败
     */
    private boolean seatDown(Seat seat) {
        seat.setSeatStatus(1);
        if (userName == null) {
            userName = userService.getUserName(userId);
        }
        seat.setSeatUser(userName);
        this.seat = seat;
//        seatService.updateSeat(seat, seat.getSeatId(), false);
        return seat.getSeatStatus() == 1 && seat.getSeatUser() != null;
    }

    /**
     * 检测未读写事件
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        super.userEventTriggered(ctx, evt);
        IOSession session = GlobalSessionContainer.getIOSession(ctx.hashCode());
        if (session == null) {
            session = this.createIOSession(ctx);
            GlobalSessionContainer.addIOSession(session);
        }
        protoPoolExecutor.userEventTriggered(session, evt);
    }

    /**
     * 服务器断开连接触发
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        IOSession session = GlobalSessionContainer.getIOSession(ctx.hashCode());
        if (session == null) {
            session = this.createIOSession(ctx);
            GlobalSessionContainer.addIOSession(session);
        }
        protoPoolExecutor.handlerRemoved(session);
    }

}



